﻿(function ($) {
    if (!$.MtoUi) {
        $.MtoUi = new Object();
    };

    $.MtoUi.CheckboxList = function (el, options) {
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;

        // Access to jQuery and DOM versions of element
        base.$el = $(el);
        base.el = el;

        // Add a reverse reference to the DOM object
        base.$el.data("MtoUi.CheckboxList", base);

        base.init = function () {
            base.options = $.extend({}, $.MtoUi.CheckboxList.defaultOptions, options);

            // Put your initialization code here 
            var multiSelect = base.$el;
            multiSelect.addClass(base.options.selectClass);
            var wrapper = $('<div></div>');
            wrapper.addClass(base.options.wrapperClass);
            wrapper.css("width", base.options.defaulControltWidth);
            multiSelect.wrapAll(wrapper);
            wrapper = multiSelect.parent();
            wrapper.append(GenerateControl(base, multiSelect));

            var dropContainerWrapper = $('<div></div>');
            dropContainerWrapper
                .addClass(base.options.dropContainerWrapperClass)
                .addClass(base.options.dropContainerWrapperHiddenClass)
                .append(GenerateDropContainer(base, multiSelect.children()))
                .append(DropContainerToolbox(base));
            wrapper.append(dropContainerWrapper);

            multiSelect
                .bind("change", { base: base }, OnSelectChange)
                .triggerHandler("change");
            wrapper.bind('click', { base: base }, OnWrapperClick);

            DisableEnableDropDownContainer(multiSelect.attr("disabled"), base);

        };

        // Sample Public Function, Uncomment to use
        //base.sampleFunction = function (){ alert('this is a sample function')};
        base.disable = function () {
            var base = this;
            DisableEnableDropDownContainer(false, base);
        };

        base.enable = function () {
            var base = this;
            DisableEnableDropDownContainer(true, base);
        };

        base.databind = function (data) {
            var base = this;
            if (data === undefined) {
                optionsList = base.$el.children();
                base.clearItems(false);
            }
            else {
                var dataArray = []
                if (data instanceof Array) {
                    dataArray = data;
                }
                else {
                    dataArray.push(data);
                }
                base.clearItems(true);
            }
            var containerWrapper = base.$el.siblings("." + this.options.dropContainerWrapperClass);
            GenerateOptions(dataArray, base.$el)
            containerWrapper.prepend(GenerateDropContainer(base, base.$el.children()));
            base.$el.triggerHandler('change');
        }

        base.clearItems = function (clearSelect) {
            var base = this;
            var containerWrapper = base.$el.siblings("." + this.options.dropContainerWrapperClass);
            if (clearSelect === undefined) {
                clearSelect = true;
            }
            if (clearSelect) {
                base.$el.children().remove();
            }
            containerWrapper.children("." + base.options.dropContainerClass).remove();
            base.$el.triggerHandler('change');
        }

        base.selectItems = function (selectedValues) {
            var base = this;
            if (!(selectedValues instanceof Array)) {
                $.error('The MtoUi.CheckboxList selectItems function require an Array of values');
            }
            $(selectedValues).each(function (index, selectedValue) {
                var itemIndex = base.$el.children("[value=" + selectedValue + "]").index();
                if (itemIndex == -1) {
                    $.error('The value(' + selectedValue + ') passed to MtoUi.CheckboxList.selectItems does not exist');
                }
                CheckUncheck(base, itemIndex, true);
            });
        }
        // Run initializer
        base.init();
    };


    //Private Function
    var pluginIsEnable = true;

    function DisableEnableDropDownContainer(isEnable, base) {
        var wrapper = base.$el.parent();
        var controlText = wrapper.find("." + base.options.controlTextClass);
        if (isEnable) {
            wrapper.removeClass(base.options.wrapperDisabledClass);
            controlText.removeAttr("disabled");
            controlText.removeAttr("readonly");
        }
        else {
            wrapper.addClass(base.options.wrapperDisabledClass);
            controlText.attr("disabled", "disabled");
            controlText.attr("readonly", "readonly");
        }
        pluginIsEnable = isEnable;
    };

    function OnWrapperClick(e) {
        if (!pluginIsEnable) {
            return;
        }
        var base = e.data.base;
        if (document.ActiveCheckBoxListSelectId != base.$el.attr('id')) {
            HideActiveCheckboxList(base);
        }
        var currentDropContainerWrapper = $(this).find("." + base.options.dropContainerWrapperClass);
        $(currentDropContainerWrapper).removeClass(base.options.dropContainerWrapperHiddenClass);
        document.ActiveCheckBoxList = currentDropContainerWrapper;
        document.ActiveCheckBoxListSelectId = base.$el.attr('id');
        $(document).bind("mousedown", { base: base }, document.HideCheckBoxList = OnDocumentMousedown);
    }

    function OnDocumentMousedown(e) {
        var base = e.data.base;
        if (!($(e.target).hasClass(base.options.wrapperClass) ||
            $(e.target).parents("." + base.options.wrapperClass).length > 0)) {
            HideActiveCheckboxList(base);
        }
    }

    function OnDropContainerCheckboxChange(e) {
        var base = e.data.base;
        var currentCheckbox = $(this);
        var wrapper = currentCheckbox.parents("." + base.options.wrapperClass);
        var optionIndex = wrapper.find(":checkbox").index(currentCheckbox);
        var option = wrapper.find("option:eq(" + optionIndex + ")");
        if (currentCheckbox.attr("checked")) {
            currentCheckbox.parent().parent().addClass(base.options.dropContainerSelectedClass);
            option.attr("selected", "selected");
        }
        else {
            currentCheckbox.parent().parent().removeClass(base.options.dropContainerSelectedClass);
            option.removeAttr("selected");
        }
        base.$el.triggerHandler("change");
    }

    function OnSelectChange(e) {
        var base = e.data.base;
        var str = "";
        var select = $(this);
        var items = select.find("option");
        var selectedList = select.find(":selected");
        if (selectedList.length == 0) {
            str = base.options.controlTextChooseText;
        }
        else if (selectedList.length == items.length) {
            str = base.options.controlTextAllSelectedText;
        }
        else if (base.options.controlTextMultipleSelectedTrigger != -1
                    && selectedList.length > base.options.controlTextMultipleSelectedTrigger) {
            str = selectedList.length + base.options.controlTextMultipleSelectedText;
        }
        else {
            selectedList.each(function (index, selected) {
                selected = $(selected);
                if (index > 0) {
                    str = str + base.options.controlTextSeparator;
                }
                str = str + selected.text();
            });
        }
        select.siblings().find("." + base.options.controlTextClass).text(str);
    }

    function OnCheckNone(e) {
        e.preventDefault();
        var base = e.data.base;
        CheckUncheckAll(base, false);

    }

    function OnCheckAll(e) {
        e.preventDefault();
        var base = e.data.base;
        CheckUncheckAll(base, true);
    }

    function HideActiveCheckboxList(base) {
        var toggle = $(document.ActiveCheckBoxList);
        toggle.addClass(base.options.dropContainerWrapperHiddenClass);
        $(document).unbind("mousedown", document.HideCheckBoxList);
    }

    function GenerateControl(base, checkboxList) {
        var control = $('<div></div>');
        control.addClass(base.options.controlClass);
        control.css("width", base.options.defaulControltWidth);

        var controlTitle = $('<span></span>');
        controlTitle.addClass(base.options.controlTextClass);
        control.append(controlTitle);
        return control;
    }


    function GenerateOptions(data, select) {
        for (var i = 0; i < data.length; i++) {
            var currentData = data[i];
            var option = $('<option></option>');
            if (currentData.value instanceof Object) {
                var optionGroup = $('<optgroup></optgroup>');
                optionGroup.attr("label", currentData.text);
                if (currentData.disabled) {
                    optionGroup.attr("disabled", "disabled");
                }
                var listoptions = GenerateOptions(currentData.value, optionGroup)
                optionGroup.append(listoptions);
                select.append(optionGroup);
            }
            else {
                option.attr("value", currentData.value);
                option.text(currentData.text);
                if (currentData.disabled) {
                    option.attr("disabled", "disabled");
                }
                if (currentData.selected) {
                    option.attr("selected", "selected");
                }
                select.append(option);
            }
        }
    }

    function GenerateDropContainer(base, options, isGroup, isGroupDisabled) {
        if (isGroup === undefined) {
            isGroup = false;
        }
        if (isGroupDisabled === undefined) {
            isGroupDisabled = false;
        }

        var divContainer = $('<div></div>');
        if (!isGroup) {
            divContainer.addClass(base.options.dropContainerClass);
        }
        else {
            divContainer.addClass(base.options.dropContainerOptionGroupWrapperClass);
        }

        var dropContainer = $('<ul></ul>');
        for (var i = 0; i < options.length; i++) {
            var currentOption = $(options[i]);
            var id = base.$el.attr("id") + "_" + currentOption.val();
            var li = $('<li></li>');
            var label = $('<label></label>');

            if (currentOption.get(0).tagName == "OPTION") {
                var checkbox = $('<input />');

                checkbox
                    .addClass(base.options.dropContainerCheckboxClass)
                    .attr("type", "checkbox")
                    .attr("id", id);

                label.append(checkbox)
                    .attr("for", id)
                    .append(currentOption.text())
                    .addClass(base.options.dropContainerLabelClass);

                if ((isGroup && isGroupDisabled) || currentOption.attr("disabled")) {
                    checkbox.attr("disabled", "disabled");
                    label.addClass(base.options.dropContainerDisabledLabelClass);
                }
            }
            else if (!isGroup && currentOption.get(0).tagName == "OPTGROUP") {
                var span = $('<span></span>');

                span.addClass(base.options.dropContainerOptionGroupClass);
                span.append(currentOption.attr("label"));
                var isCurrentgGroupDisabled = false;
                if (currentOption.attr("disabled")) {
                    span.addClass(base.options.dropContainerOptionGroupDisabledClass);
                    isCurrentgGroupDisabled = true;
                }
                li.append(span);
                li.append(GenerateDropContainer(base, currentOption.children(), true, isCurrentgGroupDisabled));
            }

            li.append(label);
            dropContainer.append(li);
        }
        dropContainer.find(":checkbox").bind("change", { base: base }, OnDropContainerCheckboxChange);

        options.parent().find(":selected").each(function (index, selected) {
            selected = $(selected)
            var id = selected.attr("value");
            var optionIndex = options.index(selected);
            var checkbox = dropContainer.find(":checkbox:eq(" + optionIndex + ")")
            checkbox
                .attr("checked", true)
                .triggerHandler("change");
        });
        divContainer.append(dropContainer);
        return divContainer;
    }

    function DropContainerToolbox(base) {
        var toolbox = $('<div></div>');
        toolbox.addClass(base.options.dropContainerToolboxClass);

        var toolBoxLabel = $('<span></span>');
        toolBoxLabel
            .addClass(base.options.dropContainerToolboxLabelClass)
            .text(base.options.dropContainerToolboxLabelText);
        toolbox.append(toolBoxLabel);

        var toolboxOptions = $('<ul></ul>');
        var optionAll = $('<li></li>');
        optionAll
                .text('Tous')
                .addClass("CheckBoxList-All")
                .bind("click", { base: base }, OnCheckAll);
        toolboxOptions.append(optionAll);
        toolboxOptions.append('<li>|</li>');
        var optionNone = $('<li></li>');
        optionNone
                .text('Aucun')
                .addClass("CheckBoxList-None")
                .bind("click", { base: base }, OnCheckNone);
        toolboxOptions.append(optionNone);
        toolbox.append(toolboxOptions);

        return toolbox;
    }

    function CheckUncheckAll(base, check) {
        var checkboxList = base.$el.siblings("." + base.options.dropContainerWrapperClass);
        checkboxList.find(":checkbox").each(function (index, currentCheckbox) {
            CheckUncheck(base, index, check);
        });
    }

    function CheckUncheck(base, itemIndex, check) {
        var currentCheckbox = base.$el.siblings().find(":checkbox:eq(" + itemIndex + ")");
        if (currentCheckbox.attr("disabled")) {
            return;
        }
        if (check) {
            currentCheckbox.attr("checked", true);
        }
        else {
            currentCheckbox.removeAttr("checked");
        }
        currentCheckbox.triggerHandler('change');
    }

    $.MtoUi.CheckboxList.defaultOptions = {
        defaulControltWidth: '300px',
        wrapperClass: 'Mto-Ui-CheckboxList-Wrapper',
        wrapperDisabledClass: 'Mto-Ui-CheckboxList-Wrapper-Disabled',
        selectClass: 'Mto-Ui-CheckboxList-Select',
        controlClass: 'Mto-Ui-CheckboxList-Control',
        controlTextClass: 'Mto-Ui-CheckboxList-Control-Text',
        dropContainerWrapperClass: 'Mto-Ui-CheckboxList-DropContainer-Wrapper',
        dropContainerWrapperHiddenClass: 'Mto-Ui-CheckboxList-DropContainer-Wrapper-Hidden',
        dropContainerClass: 'Mto-Ui-CheckboxList-DropContainer',
        dropContainerLabelClass: 'Mto-Ui-CheckboxList-DropContainer-Label',
        dropContainerDisabledLabelClass: 'Mto-Ui-CheckboxList-DropContainer-Label-Disabled',
        dropContainerOptionGroupClass: 'Mto-Ui-CheckboxList-DropContainer-OptionGroup',
        dropContainerOptionGroupDisabledClass: 'Mto-Ui-CheckboxList-DropContainer-OptionGroup-Disabled',
        dropContainerOptionGroupWrapperClass: 'Mto-Ui-CheckboxList-DropContainer-OptionGroup-Wrapper',
        dropContainerSelectedClass: 'Mto-Ui-CheckboxList-DropContainer-Selected',
        dropContainerCheckboxClass: 'Mto-Ui-CheckboxList-DropContainer-Checkbox',
        dropContainerToolboxClass: 'Mto-Ui-CheckboxList-DropContainer-Toolbox',
        dropContainerToolboxLabelClass: 'Mto-Ui-CheckboxList-DropContainer-Toolbox-Label',
        dropContainerToolboxAllClass: 'Mto-Ui-CheckboxList-Toolbox-All',
        dropContainerToolboxNoneClass: 'Mto-Ui-CheckboxList-Toolbox-None',
        dropContainerToolboxLabelText: 'Sélectionnez :',
        dropContainerToolboxAllText: 'Tous',
        dropContainerToolboxNoneText: 'Aucun',
        controlTextChooseText: 'Sélectionnez vos options',
        controlTextMultipleSelectedText: ' éléments',
        controlTextMultipleSelectedTrigger: 1,
        controlTextSeparator: ', ',
        controlTextAllSelectedText: 'Tous les éléments'
    };

    $.fn.mtoUi_CheckboxList = function (options) {
        return this.each(function () {
            var e = $(this);
            if (e.get(0).tagName == 'SELECT' && e.attr("multiple")) {
                new $.MtoUi.CheckboxList(this, options);
            } else {
                $.error('The MtoUi.CheckboxList jquery plugin works only with select tag with the multiple attribute set to multiple');
            }
        });
    };

    // This function breaks the chain, but returns
    // the MtoUi.CheckboxList if it has been attached to the object.
    $.fn.getMtoUi_CheckboxList = function () {
        this.data("MtoUi.CheckboxList");
    };

})(jQuery);